package cn.texous.web.parsing.book.manager;

import cn.texous.util.commons.util.CollectionUtils;
import cn.texous.util.commons.util.GsonUtils;
import cn.texous.web.parsing.book.common.constants.NormalStatusEnum;
import cn.texous.web.parsing.book.common.constants.OriginDetailRequestTypeEnum;
import cn.texous.web.parsing.book.common.constants.OriginDetailTypeEnum;
import cn.texous.web.parsing.book.model.entity.mysql.AnaOrigin;
import cn.texous.web.parsing.book.model.entity.mysql.AnaOriginDetail;
import cn.texous.web.parsing.book.model.entity.mysql.AnaOriginDetailField;
import cn.texous.web.parsing.book.model.entity.mysql.AnaOriginDetailRequest;
import cn.texous.web.parsing.book.model.json.self.SelfBaseInfo;
import cn.texous.web.parsing.book.model.json.self.SelfBook;
import cn.texous.web.parsing.book.model.json.self.SelfBookInfo;
import cn.texous.web.parsing.book.model.json.self.SelfCatalogInfo;
import cn.texous.web.parsing.book.model.json.self.SelfChapterInfo;
import cn.texous.web.parsing.book.model.json.self.SelfFieldInfo;
import cn.texous.web.parsing.book.model.json.self.SelfHttpInfo;
import cn.texous.web.parsing.book.service.api.mysql.AnaOriginDetailFieldService;
import cn.texous.web.parsing.book.service.api.mysql.AnaOriginDetailRequestService;
import cn.texous.web.parsing.book.service.api.mysql.AnaOriginDetailService;
import cn.texous.web.parsing.book.service.api.mysql.AnaOriginService;
import com.google.gson.reflect.TypeToken;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2020/3/9 20:13
 */
@Component
@AllArgsConstructor
public class OriginManager {

    private AnaOriginService anaOriginService;
    private AnaOriginDetailService anaOriginDetailService;
    private AnaOriginDetailRequestService anaOriginDetailRequestService;
    private AnaOriginDetailFieldService anaOriginDetailFieldService;

    /**
     * 将数据源字符串解析到数据库
     *
     * @param origins 数据源字符串
     * @return
     */
    public boolean parseOrigins(String origins) {
        List<SelfBook> values = GsonUtils
                .fromJson(origins, new TypeToken<List<SelfBook>>() {
                }.getType());
        values.forEach(this::storeToMysql);
        return true;
    }

    public void storeToMysql(SelfBook selfBook) {
        // TODO 处理重复数据源问题
        SelfBaseInfo baseInfo = selfBook.getBaseInfo();
        AnaOrigin origin = new AnaOrigin();
        origin.setCharset(baseInfo.getCharset());
        origin.setCode(selfBook.getOrigin());
        origin.setCustomizeHeader(baseInfo.getCustomizeHeader() == null
                || baseInfo.getCustomizeHeader().isEmpty()
                ? null : GsonUtils.toJson(baseInfo.getCustomizeHeader()));
        origin.setDatePattern(baseInfo.getDatePattern() == null
                ? "yyyy-MM-dd HH:mm:ss"
                : baseInfo.getDatePattern());
        origin.setDescription(baseInfo.getDescription());
        origin.setDomain(baseInfo.getDomain());
        origin.setDyn(BooleanUtils.toInteger(baseInfo.getDynamicAnalysis()));
        origin.setName(selfBook.getOrigin());
        origin.setOpenDookies(BooleanUtils.toInteger(baseInfo.getOpenCookies()));
        origin.setOpenHttps(BooleanUtils.toInteger(baseInfo.getOpenSSL()));
        origin.setRespType(baseInfo.getRespType());
        origin.setRetry(baseInfo.getRetry() == null
                ? 0 : baseInfo.getRetry());
        origin.setStatus(NormalStatusEnum.AVAILABLE.getCode());
        origin.setUrlEncoder(baseInfo.getUrlEncoder());
        origin.setWeights(baseInfo.getWeights() == null
                ? 0 : baseInfo.getWeights());
        anaOriginService.save(origin);

        SelfBookInfo bookInfo = selfBook.getBookInfo();
        storeOriginDetailToMysql(origin.getId(), bookInfo.getDataPattern(), bookInfo.getRetry(),
                bookInfo.getWeights(), bookInfo.getHttpInfo(), bookInfo.getNextPageInfo(),
                bookInfo.getFieldInfos(), OriginDetailTypeEnum.FICTION);

        SelfCatalogInfo catalogInfo = selfBook.getCatalogInfo();
        storeOriginDetailToMysql(origin.getId(), catalogInfo.getDataPattern(), catalogInfo.getRetry(),
                catalogInfo.getWeights(), catalogInfo.getHttpInfo(), catalogInfo.getNextPageInfo(),
                catalogInfo.getFieldInfos(), OriginDetailTypeEnum.CATALOG);

        SelfChapterInfo chapterInfo = selfBook.getChapterInfo();
        storeOriginDetailToMysql(origin.getId(), chapterInfo.getDataPattern(), chapterInfo.getRetry(),
                chapterInfo.getWeights(), chapterInfo.getHttpInfo(), chapterInfo.getNextPageInfo(),
                chapterInfo.getFieldInfos(), OriginDetailTypeEnum.CHAPTER);

    }

    private void storeOriginDetailToMysql(Integer originId, String datePattern,
                                          Integer retry, Integer weights,
                                          SelfHttpInfo httpInfo, SelfHttpInfo nextPageInfo,
                                          List<SelfFieldInfo> selfFieldInfos,
                                          OriginDetailTypeEnum detailTypeEnum) {
        AnaOriginDetail fictionInfo = new AnaOriginDetail();
        fictionInfo.setAnaOriginId(originId);
        fictionInfo.setDatePattern(datePattern);
        fictionInfo.setRetry(retry == null ? 0 : retry);
        fictionInfo.setStatus(NormalStatusEnum.AVAILABLE.getCode());
        fictionInfo.setType(detailTypeEnum.getCode());
        fictionInfo.setWeights(weights == null ? 0 : weights);
        anaOriginDetailService.save(fictionInfo);

        AnaOriginDetailRequest fictionRequest = generatorRequest(
                httpInfo, fictionInfo.getId(), OriginDetailRequestTypeEnum.NORMAL);
        anaOriginDetailRequestService.save(fictionRequest);
        AnaOriginDetailRequest fictionNextRequest = generatorRequest(
                nextPageInfo, fictionInfo.getId(), OriginDetailRequestTypeEnum.NEXT);
        anaOriginDetailRequestService.save(fictionNextRequest);

        storeOriginDetailFieldToMysql(selfFieldInfos, fictionInfo.getId(), 0);
    }

    private void storeOriginDetailFieldToMysql(List<SelfFieldInfo> selfFieldInfos,
                                               Integer originDetailId, Integer parentId) {
        for (SelfFieldInfo selfFieldInfo : selfFieldInfos) {
            AnaOriginDetailField field = new AnaOriginDetailField();
            field.setAnaOriginDetailId(originDetailId);
            field.setClassName(selfFieldInfo.getClassName());
            field.setField(selfFieldInfo.getField());
            field.setIsLeaf(BooleanUtils.toInteger(
                    CollectionUtils.isEmpty(selfFieldInfo.getChilds())));
            field.setParentId(parentId);
            field.setXPath(selfFieldInfo.getXPath());
            anaOriginDetailFieldService.save(field);
            if (CollectionUtils.isNotEmpty(selfFieldInfo.getChilds())) {
                storeOriginDetailFieldToMysql(
                        selfFieldInfo.getChilds(), originDetailId, field.getId());
            }
        }
    }

    private AnaOriginDetailRequest generatorRequest(SelfHttpInfo fictionHttpInfo,
                                                    Integer originDetailId,
                                                    OriginDetailRequestTypeEnum typeEnum) {
        AnaOriginDetailRequest fictionRequest = new AnaOriginDetailRequest();
        fictionRequest.setAnaOriginDetailId(originDetailId);
        fictionRequest.setInCharset(fictionHttpInfo.getInCharset());
        fictionRequest.setMethod(fictionHttpInfo.getMethod());
        fictionRequest.setOutCharset(fictionHttpInfo.getOutCharset());
        fictionRequest.setParam(fictionHttpInfo.getParams() == null
                || fictionHttpInfo.getParams().isEmpty()
                ? null : GsonUtils.toJson(fictionHttpInfo.getParams()));
        fictionRequest.setStatus(NormalStatusEnum.AVAILABLE.getCode());
        fictionRequest.setType(typeEnum.getCode());
        fictionRequest.setUrl(fictionHttpInfo.getUrl());
        fictionRequest.setUrlEncoder(fictionHttpInfo.getUrlEncoder());
        return fictionRequest;
    }

}
